/*


*/
package melwi;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

class Generator {
	private int[] tones; //zadani,preda cteni
	/*
	private int[] Nastroj.harmonizing={4,9,2,7,11,4}
	private int Nastroj.stringBas=3; //to se dedi!!!!!!!!!!!!!!!!!!
	private static int Nastroj.tonesNum=12;
	private int Nastroj.fretNum=14; //prazec
	private int Nastroj.stringNum=6;
	private int Nastroj.konstBas=5;
	
	private int Nastroj.fingerMax=4;
	private int Nastroj.fretMax=3;
	*/

	private int[][] krk = new int[Nastroj.stringNum][Nastroj.fretNum+1];
	private int[] mezivysledek = new int[Nastroj.stringNum];
	private int[] nejmensi = new int[Nastroj.stringNum];
	private int[] nejvetsi= new int[Nastroj.stringNum];
	
	TreeSet<Hmat> akord=new TreeSet<Hmat>(new Komp()); //je to private?!!!!!!!!!!
	
	//public static void main(String args[]){new Generator();}
public Generator (int[] tones){
	/**
	 *generovani krku
	  */
	
	this.tones=new int[tones.length];
	for(int i=0;i<tones.length;i++){
		this.tones[i]=tones[i];
	}
	for(int i=0; i<Nastroj.stringNum;i++){
		for(int j=0; j<=Nastroj.fretNum; j++){
			krk[i][j]=(Nastroj.harmonizing[i]+j)%Nastroj.tonesNum;
		}
	} 

	permutation(0, tones, mezivysledek, nejmensi, nejvetsi);
	printSetOfAkord(akord);

	Hmat[] poleB=this.getArray();
	Kreslitko aktkreslitko = new Kreslitko("Akordy", poleB);

}

public Generator (int[] tones, int bass){
	
	this.tones=new int[tones.length];
	for(int i=0;i<tones.length;i++){
		this.tones[i]=tones[i];
	}
	for(int i=0; i<Nastroj.stringNum;i++){
		for(int j=0; j<=Nastroj.fretNum; j++){
			krk[i][j]=(Nastroj.harmonizing[i]+j)%Nastroj.tonesNum;
		}
	} 

	permutationBas(0, tones, mezivysledek, nejmensi, nejvetsi, bass);
	printSetOfAkord(akord);

	Hmat[] poleB=this.getArray();
	Kreslitko aktkreslitko = new Kreslitko("Akordy", poleB);

}


	public Hmat[] getArray(){
		return akord.toArray(new Hmat[0]);
	}

	private void permutation(int string, int zadani[], int mezivystup[], int nejmensi[], int nejvetsi[]){
		System.out.println("permutace" + (string)); //jakasi podivna kontrola na jake jsem strune
		
		for(int q=0; q<zadani.length; q++){ //tady jsou zadane tony, co mam hledat, pole
			for(int s=0; s<=Nastroj.fretNum; s++){ //jdu po prazcich od nulteho nahoru a koukam, jestli na te strune nejsou ty tony
				if(krk[string][s]==zadani[q]){ //jsou-li tam, tak zkoumam ty prazce, jestli roztahnu dost prsty
					if (string==0){ //ukladam hodnoty nejmensich a nejvetsich prazcu, osetruji, kdyz jsem na prvni strune
						if(s!=0){
							nejmensi[string]=s;
							nejvetsi[string]=s;
						}	
						else{
							nejmensi[string]=Nastroj.fretNum+1; //zajisteni, aby nadale nedochazelo k chybne interpretaci nejmensiho prazce
							nejvetsi[string]=1; //urcite jednicka?!!!!!!
						}
					}
					else{
							if(s>0 && s<nejmensi[string-1]){
								nejmensi[string]=s;
							}
							else{
								nejmensi[string]=nejmensi[string-1];
							}
							if(s>0 && s>nejvetsi[string-1]){
								nejvetsi[string]=s;
							}
							else{
								nejvetsi[string]=nejvetsi[string-1];
							}
					}
						if(nejvetsi[string]-nejmensi[string]<=Nastroj.fretMax){ //pokud jsou prazce dost blizko k sobe, tak nalezeny ton ulozim do mezivystupu
							mezivystup[string]=s;
							if(string+1<Nastroj.stringNum){ //poustim to na dalsi strunu
								permutation(string+1, zadani, mezivystup, nejmensi, nejvetsi);
							}
							else{ //jsou-li vsechny struny, testuji
								for(int x=0;x<Nastroj.stringNum;x++){
									System.out.print(mezivystup[x]+" ");
								} //kontrolni vypis
								System.out.println(nejmensi[Nastroj.stringNum-1]);


								if(fingerTest(mezivystup, nejmensi[Nastroj.stringNum-1]) && tonesTest(zadani, mezivystup)){ //testy na pocet prstu a na uziti vsech tonu
									System.out.println("proslo testem");
									Hmat h=new Hmat(mezivystup, nejmensi[Nastroj.stringNum-1]);
								//generuji z toho hmat
									akord.add(h); //vkladam do setu
		
						
								/*
								System.out.println("vypis setu jeste jednou");
								printSetOfAkord(akord);
*/
								/*for(int x=0;x<Nastroj.stringNum;x++){
								System.out.print(mezivystup[x]+" ");
								}
								System.out.println(nejmensi[Nastroj.stringNum-1]);
								*/



								//System.out.println("pridavam do setu"+" "+h);
								//!!!!!!!!!! pridej do setu
								//!!!!!!!! co s tim nejmensim prvkem?
							}
						}
					}
				}
			}
		}
	}

	private void permutationBas(int string, int zadani[], int mezivystup[], int nejmensi[], int nejvetsi[], int bass){
		for(int q=0; q<zadani.length; q++){
			for(int s=0; s<=Nastroj.fretNum; s++){
				if(krk[string][s]==zadani[q]){
					if (string==0){
						if(s!=0){
							nejmensi[string]=s;
							nejvetsi[string]=s;
						}	
						else{
							nejmensi[string]=Nastroj.fretNum+1; //zajisteni, aby nadale nedochazelo k chybne interpretaci nejmensiho prazce
							nejvetsi[string]=0;
						}
					}
					else{
						if(s>0 && s<nejmensi[string-1]){
							nejmensi[string]=s;
						}
						else{
							nejmensi[string]=nejmensi[string-1];
						}
						if(s>0 && s>nejvetsi[string-1]){
							nejvetsi[string]=s;
						}
						else{
							nejvetsi[string]=nejvetsi[string-1];
						}
					}
					if(nejvetsi[string]-nejmensi[string]<=Nastroj.fretMax+Nastroj.konstBas){
						mezivystup[string]=s;
						if(string+1<Nastroj.stringNum){
							permutationBas(string+1, zadani, mezivystup, nejmensi, nejvetsi,bass);}
						else{ 
							basovka(mezivystup, zadani, nejmensi, nejvetsi, bass);	
								//!!!!!!!! co s tim nejmensim prvkem?
						}
					}
				}
			}
		}
	}

	private boolean tonesTest(int zadaniT[], int vysledek[]){
		boolean[] test= new boolean[zadaniT.length];
		boolean b=true;

		for(int i=0; i<zadaniT.length; i++){
			for(int j=0; j<vysledek.length; j++){
				if (krk[j][vysledek[j]]==zadaniT[i]){ //zkontrolovat indexy!!!!!
					test[i]=true;
				}
			}
		}
		for(int k=0; k<zadaniT.length; k++){
			if(! test[k]){b=false;}
		}
		return b;
	}

	private boolean fingerTest(int vysledek[], int minimum){
		int fingNum=0;
		for(int i=0; i<Nastroj.stringNum; i++){
			if(vysledek[i]>0){
			fingNum++;}
		}
		if (fingNum>Nastroj.fingerMax){
			return barreTest(fingNum, vysledek, minimum);
		}
		else {return true;}
	}

	private boolean barreTest(int fingNum, int vysledek[], int minimum){
		boolean b=false;
		for(int i=2; i<=Nastroj.stringNum; i++){ //kolik strun bude v barre
			int fingBarre=0;
			for(int j=Nastroj.stringNum-1; j>=Nastroj.stringNum-i; j--){ //odspoda zkoumam, jestli lze udelat barre
				if(vysledek[j]==minimum){
					fingBarre++;
				}
			}
			if(fingNum-fingBarre+1<=Nastroj.fingerMax){ //pokud barre usetri dost prstu, overim, ze nikde nejde pres prazdnou strunu
				b=true;
				for(int k=Nastroj.stringNum-1; k>=Nastroj.stringNum-i; k--){
					if (vysledek[k]==0){
						b=false;
					}

				}
			}
			if(b){break;}
		}
		return b;
	}

//k cemu tady ty nejmensi a nejvetsi?
	private void basovka(int mezivystup[], int zadani[], int nejmensi[], int nejvetsi[], int bas){
		int[] mezivystupA  = new int[Nastroj.stringNum];
		for(int i=0; i<Nastroj.stringBas; i++){
			for(int p=0; p<=Nastroj.fretNum; p++){
				if(krk[i][p]==bas){
					for(int k=0; k<Nastroj.stringNum;k++){
						mezivystupA[k]=mezivystup[k];
					}
					
					mezivystupA[i]=p;
				
					int min=Nastroj.fretNum+2;
					int max=0;
					for(int j=0; j<Nastroj.stringNum; j++){
						if(mezivystupA[j]>max){
							max=mezivystupA[j];
						}
						if(mezivystupA[j]<min && mezivystupA[j]!=0){
							min=mezivystupA[j];
						}
					}
					if(max-min<=Nastroj.fretMax){
						if(fingerTest(mezivystupA, min) && tonesTest(zadani, mezivystupA)){
							Hmat h=new Hmat(mezivystupA, min);
							akord.add(h);
						}
					}
				}
			}
		}	
	}

	public void printSetOfAkord(SortedSet<Hmat> akord){
		System.out.println("tisknu set zaciname"); //odstanit!!!!!!!!!
		for(Hmat h: akord){
			System.out.println(h.toString());
		}
		System.out.println("tisknu set hotovo"); //odstanit!!!!!!!!!
	}



}
